package com.fas.core;

import java.lang.reflect.Field;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.junit.Assert;

import com.fas.core.constant.R;
import com.fas.core.plugin.datatables.PageConstants;
import com.fas.core.plugin.datatables.PageRequest;
import com.fas.core.plugin.datatables.PageResponse;
import com.fas.core.plugin.jfinal.route.ControllerBind;
import com.fas.core.plugin.shiro.kit.FasShiroKit;
import com.fas.core.web.response.JSONResult;
import com.fas.core.web.response.Result;
import com.fas.core.web.response.ResultStatus;
import com.fas.hehe.system.model.LoginUser;
import com.jfinal.aop.Before;
import com.jfinal.core.Controller;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.jfinal.plugin.activerecord.tx.Tx;

/**
 * 
 * @ClassName: BaseController
 * @Description: 控制器基类
 * @Copyright: Copyright (c) 2016 FAS
 * @anthor yixiaoping<thinker1013@163.com>
 * @since 2016年1月24日 下午11:02:57
 * @version V1.0
 */
public class BaseController extends Controller {
	protected Log log = Log.getLog(this.getClass());
	protected String controllerKey;
	protected String viewPath;
	protected boolean saveOperateLog = true;
	protected Class<? extends Model> modelClass;
	protected Model<?> modelEntity;
	protected String modelSimpleName;
	protected LoginUser loginUser;
	protected final static String LIST_PAGE = "list.jsp";
	protected final static String SELECT_PAGE = "select.jsp";
	protected final static String EDIT_PAGE = "edit.jsp";
	protected final static String RESULT_PAGE = "/page/public/public-result.jsp";
	protected boolean SUCCESS = true;
	protected boolean ERROR = false;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void initService() {
		Field[] fields = this.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];
			Class clazz = field.getType();
			if (Service.class.isAssignableFrom(clazz) && clazz != Service.class) {
				try {
					if (!field.isAccessible()) {
						field.setAccessible(true);
					}

					field.set(this, Service.getInstance(clazz, this));
				} catch (IllegalAccessException e) {
					log.error("Controller自动注入Service异常", e);
				}
			}
		}
	}

	public BaseController() {
		ControllerBind controllerBind = this.getClass().getAnnotation(ControllerBind.class);
		this.controllerKey = controllerBind.controllerKey();
		this.viewPath = controllerBind.viewPath() == null ? controllerKey : controllerBind.viewPath();
		this.initService();
	}

	/**
	 * 根据主键查询对象
	 */
	public Model<?> findById(Object... idValues) {
		try {
			this.modelEntity = this.getModelEntity().findById(idValues);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return this.modelEntity;
	}

	/**
	 * 跳转到【列表页面】
	 */
	public void show() throws Exception {
		this.beforeShow();
		render(LIST_PAGE);
	}

	/**
	 * 跳转到【选择页面】
	 */
	public void select() throws Exception {
		this.beforeShow();
		render(SELECT_PAGE);
	}

	/**
	 * 跳转到【新增页面】
	 */
	public void add() throws Exception {
		this.beforeAdd();
		this.setAttr(R.Key.IS_NEW, R.Const.TRUE);
		this.setAttr(R.Key.IS_EDIT, R.Const.TRUE);
		this.setAttr(R.Key.OPER_TYPE, R.OperType.ADD.getName());
		render(EDIT_PAGE);
	}

	/**
	 * 跳转到【修改页面】
	 */
	public void edit() throws Exception {
		Assert.assertNotNull("主键为空", this.getPara(R.Key.PK));
		this.modelEntity = this.getModelEntity().findById(this.getPara(R.Key.PK));

		Assert.assertNotNull("查询数据为空", this.modelEntity);
		this.beforeEdit();

		this.setAttr(this.getModelSimpleName(), modelEntity);
		this.setAttr(R.Key.IS_NEW, R.Const.FALSE);
		this.setAttr(R.Key.IS_EDIT, R.Const.TRUE);
		this.setAttr(R.Key.OPER_TYPE, R.OperType.UPDATE.getName());
		render(EDIT_PAGE);
	}

	/**
	 * 跳转到【查看页面】
	 */
	public void view() throws Exception {
		Assert.assertNotNull("主键为空", this.getPara(R.Key.PK));
		this.modelEntity = this.getModelEntity().findById(this.getPara(R.Key.PK));

		Assert.assertNotNull("查询数据为空", this.modelEntity);
		this.setAttr(this.getModelSimpleName(), modelEntity);

		this.beforeView();
		this.setAttr(R.Key.IS_NEW, R.Const.FALSE);
		this.setAttr(R.Key.IS_EDIT, R.Const.FALSE);
		this.setAttr(R.Key.OPER_TYPE, R.OperType.VIEW.getName());
		render(EDIT_PAGE);
	}

	/**
	 * 通用保存
	 */
	@Before(Tx.class)
	public void save() throws Exception {
		String isNew = this.getPara(R.Key.IS_NEW);
		this.modelEntity = this.getModelEntity();
		if (R.Const.TRUE.equals(isNew)) {
			this.beforeSave();
			this.modelEntity.save();

			BaseService service = enhance(BaseService.class);
			if (saveOperateLog) {
				service.saveOperateLog(R.OperType.ADD, modelEntity, null, this.getLoginUser());
			}
			this.afterSave();
			this.addSuccessMessage("新增成功");
		} else {
			this.beforeUpdate();
			Table table = TableMapping.me().getTable(this.getModelEntity().getClass());

			String[] primaryKey = table.getPrimaryKey();
			Object pkValue = this.getModelEntity().get(primaryKey[0]);
			Model<?> oldModelEntity = this.getModelEntity().findById(pkValue);

			this.modelEntity.update();
			BaseService service = enhance(BaseService.class);

			if (saveOperateLog) {
				service.saveOperateLog(R.OperType.UPDATE, modelEntity, oldModelEntity, this.getLoginUser());
			}
			this.afterUpdate();
			this.addSuccessMessage("修改成功");
		}
		this.setAttr(R.Key.IS_NEW, false);
		this.setAttr(R.Key.IS_EDIT, false);
		this.keepModel(modelClass);

		render(RESULT_PAGE);
	}

	/**
	 * 通用删除
	 */
	@Before(Tx.class)
	public void delete() throws Exception {
		this.beforeDelete();
		Object[] primaryKeys = (Object[]) this.getParaValues(R.Key.PK);

		Assert.assertNotNull("主键为空", primaryKeys);
		for (Object primaryKey : primaryKeys) {
			modelEntity = this.getModelEntity().findById(primaryKey);
			this.getModelEntity().deleteById(primaryKey);

			BaseService service = enhance(BaseService.class);
			if (saveOperateLog) {
				service.saveOperateLog(R.OperType.DELETE, modelEntity, null, this.getLoginUser());
			}
		}

		this.afterDelete();
		render(LIST_PAGE);
	}

	protected PageRequest pageRequest;

	protected PageRequest buildPageRequest() {
		pageRequest = new PageRequest();
		try {
			HttpServletRequest request = this.getRequest();
			String jsondata = (String) request.getParameter(PageConstants.JSON_PARAM_AODATA);

			int sEcho = PageConstants.DEFAULT_SECHO;
			int iDisplayStart = PageConstants.DEFAULT_IDISPLAYSTART;
			int iDisplayLength = PageConstants.DEFAULT_IDISPLAYLENGTH;
			String sColumns = "";
			String orderColumn = null;
			String order = PageConstants.DEFAULT_ORDERBY;

			// 解析jquery datatables 异步查询JSON数据结构
			HashMap<String, Object> pageParamsMap = new HashMap<String, Object>();
			if (StrKit.notBlank(jsondata)) {
				JSONArray jsonarray = JSONArray.fromObject(jsondata);
				for (int i = 0; i < jsonarray.size(); i++) {
					JSONObject obj = (JSONObject) jsonarray.get(i);
					pageParamsMap.put(obj.get(PageConstants.JSON_PARAM_NAME).toString(),
							obj.get(PageConstants.JSON_PARAM_VALUE));
				}
				sEcho = (Integer) pageParamsMap.get(PageConstants.JSON_PARAM_SECHO);// sEcho
				iDisplayStart = (Integer) pageParamsMap.get(PageConstants.JSON_PARAM_IDISPLAYSTART);// 第几页
				iDisplayLength = (Integer) pageParamsMap.get(PageConstants.JSON_PARAM_IDISPLAYLENGTH);// 每页显示多少记录
				sColumns = (String) pageParamsMap.get(PageConstants.JSON_PARAM_SCOLUMNS);// 前台显示字段name数组

				int iSortCol_0 = 0;
				if (pageParamsMap.get(PageConstants.JSON_PARAM_ISORTCOL_O) != null) {
					iSortCol_0 = (Integer) pageParamsMap.get(PageConstants.JSON_PARAM_ISORTCOL_O);// 排序列在列名索引
					order = (String) pageParamsMap.get(PageConstants.JSON_PARAM_SSORTDIR_O);// 排序方式
				}

				String[] colArray = sColumns.split(",");
				if (colArray.length > iSortCol_0) {
					orderColumn = colArray[iSortCol_0];
				}
			}

			// 设置排序信息
			StringBuffer orderby = new StringBuffer();
			if (StrKit.notBlank(orderColumn)) {
				orderby.append(orderColumn).append(" ").append(order);
			}

			// 设置分页信息
			pageRequest.setsEcho(sEcho);
			pageRequest.setPageNumber(iDisplayStart / iDisplayLength + 1);
			pageRequest.setPageSize(iDisplayLength);
			pageRequest.setOderby(orderby.toString());
			pageRequest.setParams(getParametersAll(request));

		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return pageRequest;
	}

	/**
	 * 
	 * @Title:分页查询数据返回
	 * @Description: TODO
	 * @param page
	 * @throws Exception
	 * @anthor yixiaoping<thinker163@163.com>
	 * @date 2015年10月16日 下午5:28:08
	 */
	protected void returnPage(Page<Record> recordList) {
		PageResponse pageResponse = new PageResponse();
		pageResponse.setAaData(recordList.getList());
		pageResponse.setITotalDisplayRecords(recordList.getTotalRow());
		pageResponse.setITotalRecords(recordList.getTotalRow());
		pageResponse.setSEcho(pageRequest.getsEcho());

		String json = JsonKit.toJson(pageResponse);
		renderJson(json);
	}

	/**
	 * 跳转到【列表页面】之前预处理
	 */
	protected void beforeShow() throws Exception {
	}

	/**
	 * 在新增操作之前业务处理
	 */
	protected void beforeAdd() throws Exception {
	}

	/**
	 * 在查看操作之前业务处理
	 */
	protected void beforeView() throws Exception {
	}

	/**
	 * 在修改操作之前业务处理
	 */
	protected void beforeEdit() throws Exception {
	}

	/**
	 * 在保存操作之前业务处理
	 */
	protected void beforeSave() throws Exception {
	}

	/**
	 * 在保存操作之后业务处理
	 */
	protected void afterSave() throws Exception {
	}

	/**
	 * 在修改操作之前业务处理
	 */
	protected void beforeUpdate() throws Exception {
	}

	/**
	 * 在修改操作之后业务处理
	 */
	protected void afterUpdate() throws Exception {
	}

	/**
	 * 在删除操作之前业务处理
	 */
	protected void beforeDelete() throws Exception {
	}

	/**
	 * 在删除操作之后业务处理
	 */
	protected void afterDelete() throws Exception {
	}

	public Class<? extends Model> getModelClass() {
		try {
			if (modelClass == null) {
				String controllerClass = this.getClass().getName();
				String modelClassName = StringUtils.substringBeforeLast(controllerClass, "Controller").replaceAll(
						"\\.controller\\.", ".model.");
				modelClass = (Class<? extends Model>) Class.forName(modelClassName).newInstance().getClass();
			}
		} catch (Exception e) {
			log.error("操作异常:", e);
			this.setAttr("message", "获取Model class异常:" + e.getMessage());
		}
		return modelClass;
	}

	public void setModelClass(Class<? extends Model> modelClass) {
		this.modelClass = modelClass;
	}

	public Model<?> getModelEntity() throws Exception {
		if (null == modelEntity) {
			modelEntity = (Model<? extends Model>) this.getModel(getModelClass(), this.getModelSimpleName());
		}
		return modelEntity;
	}

	public void setModelEntity(Model<?> modelEntity) {
		this.modelEntity = modelEntity;
	}

	public LoginUser getLoginUser() {
		return FasShiroKit.loginUser();
	}

	public void setLoginUser(LoginUser loginUser) {
		this.loginUser = loginUser;
	}

	public String captureName(String name) {
		name = name.substring(0, 1).toLowerCase() + name.substring(1);
		return name;
	}

	public String getModelSimpleName() {
		modelSimpleName = captureName(getModelClass().getSimpleName());
		return modelSimpleName;
	}

	public void setModelSimpleName(String modelSimpleName) {
		this.modelSimpleName = modelSimpleName;
	}

	/**
	 * 取得所有Request Parameters.
	 */
	public static Map<String, Object> getParametersAll(ServletRequest request) {
		Enumeration<?> paramNames = request.getParameterNames();
		Map<String, Object> params = new HashMap<String, Object>();
		while (paramNames != null && paramNames.hasMoreElements()) {
			String paramName = (String) paramNames.nextElement();
			String[] values = request.getParameterValues(paramName);
			if (values == null || values.length == 0) {
			} else if (values.length > 1) {
				params.put(paramName, values);
			} else {
				params.put(paramName, values[0]);
			}
		}
		return params;
	}

	private void addSuccessMessage(String message) {
		this.setAttr(R.Key.DEFAULT_MSGTAG_KEY, new Result(ResultStatus.SUCCESS, message));
		if (StrKit.notBlank(controllerKey) && controllerKey.endsWith("/")) {
			this.setAttr(R.Key.REDIRECT_URL, controllerKey + "show");
		} else {
			this.setAttr(R.Key.REDIRECT_URL, controllerKey + "/" + "show");
		}

	}

	public void renderToResultPage(String message) {
		this.setAttr(R.Key.DEFAULT_MSGTAG_KEY, new Result(ResultStatus.SUCCESS, message));
		if (StrKit.notBlank(controllerKey) && controllerKey.endsWith("/")) {
			this.setAttr(R.Key.REDIRECT_URL, controllerKey + "show");
		} else {
			this.setAttr(R.Key.REDIRECT_URL, controllerKey + "/" + "show");
		}
		render(RESULT_PAGE);
	}

	public void returnJsonResult(boolean isSuccess) {
		if (isSuccess) {
			this.returnJsonResultSuccess("操作成功", null);
		} else {
			this.returnJsonResultError("操作失败", null);
		}
	}

	public void returnJsonResult(Object returnData) {
		this.returnJsonResultSuccess("操作成功", returnData);
	}

	public void returnJsonResult(boolean isSuccess, String message, Object returnData) {
		if (isSuccess) {
			this.returnJsonResultSuccess(message, returnData);
		} else {
			this.returnJsonResultError(message, returnData);
		}
	}

	private void returnJsonResultSuccess(String message, Object returnData) {
		this.returnJsonResult(ResultStatus.SUCCESS, message, returnData);
	}

	private void returnJsonResultError(String message, Object returnData) {
		this.returnJsonResult(ResultStatus.ERROR, message, returnData);
	}

	private void returnJsonResult(ResultStatus stutus) {
		this.returnJsonResult(stutus, null, null);
	}

	private void returnJsonResult(ResultStatus stutus, String message, Object returnData) {
		JSONResult jsonResult = new JSONResult(stutus, message, returnData);
		this.renderJson(jsonResult);
	}

}
